package com.ruoyi.xag.service.impl;

import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.utils.MyDateUtil;
import com.ruoyi.xag.domain.SoilData;
import com.ruoyi.xag.domain.WeatherData;
import com.ruoyi.xag.domain.datapoints.SoilSenorDataPoints;
import com.ruoyi.xag.domain.datapoints.WeatherSenorDataPoints;
import com.ruoyi.xag.domain.iotdevice.IotDevice;
import com.ruoyi.xag.mapper.DataMapper;
import com.ruoyi.xag.service.DataService;
import com.ruoyi.xag.service.DeviceService;
import com.ruoyi.xag.service.SessionService;
import com.ruoyi.xag.utils.CreateSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @author LiSuxuan
 * @date 2021年 07月 09日 17:13
 */
@Service
public class DataServiceImpl implements DataService {

    @Autowired
    private DataMapper dataMapper;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private SessionService sessionService;

    /**
     * IOT 客户唯一ID
     */
    @Value("${iot.clientId}")
    private String clientId;

    /**
     * IOT 设备密钥
     */
    @Value("${iot.secret}")
    private String secret;

    /**
     * IOT 设备密钥
     */
    @Value("${iot.iotUrl}")
    private String iotUrl;

    /**
     * IOT 用户ID
     */
    @Value("${iot.account}")
    private String account;


    /**
     * @param deviceId  设备ID
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 每天数据列表
     */
    @Override
    public List<WeatherData> weatherDataStatistics(String deviceId, String startTime, String endTime) {
        /* 计算时间间隔，按 天 存入 集合 */
        List<String> dates = MyDateUtil.calculateTimeInterval(startTime, endTime);
        if (dates == null) {
            return null;
        }
        List<WeatherData> statistics = new ArrayList<>();
        for (String date : dates) {
            // 转换为 unix 时间
            int unixStartTime = Math.toIntExact(MyDateUtil.date2UnixTime(date, "yyyy-MM-dd"));
            int unixEndTime = unixStartTime + 86400;
            // 属性集合
            List<Float> temperatureList = new ArrayList<>();
            List<Float> humidityList = new ArrayList<>();
            List<Float> pressureList = new ArrayList<>();
            List<Float> illuminationList = new ArrayList<>();
            List<Float> rainfallList = new ArrayList<>();
            List<Float> windSpeedList = new ArrayList<>();
            WeatherData weatherData = new WeatherData();
            weatherData.setDate(date);
            List<WeatherSenorDataPoints> weatherSenorDataPoints = deviceService.selectWeatherHistoryData(deviceId, unixStartTime, unixEndTime);
            if (weatherSenorDataPoints.size() != 0) {
                // 装载集合
                for (WeatherSenorDataPoints weatherSenorDataPoint : weatherSenorDataPoints) {
                    temperatureList.add(weatherSenorDataPoint.getData().getTemperature());
                    humidityList.add(weatherSenorDataPoint.getData().getHumidity());
                    pressureList.add(weatherSenorDataPoint.getData().getPressure());
                    illuminationList.add(weatherSenorDataPoint.getData().getIllumination());
                    rainfallList.add(weatherSenorDataPoint.getData().getRainfall());
                    windSpeedList.add(weatherSenorDataPoint.getData().getWind_speed());
                }
                // 清除空值 防止下一步判断错误
                temperatureList.removeIf(Objects::isNull);
                humidityList.removeIf(Objects::isNull);
                pressureList.removeIf(Objects::isNull);
                illuminationList.removeIf(Objects::isNull);
                rainfallList.removeIf(Objects::isNull);
                windSpeedList.removeIf(Objects::isNull);

                // set 最大、最小、平均值
                weatherData.setTemperatureMax(keepTwoDecimalPlaces(Collections.max(temperatureList)))
                        .setTemperatureMin(keepTwoDecimalPlaces(Collections.min(temperatureList)))
                        .setTemperatureAverage(getListAverage(temperatureList));
                weatherData.setHumidityMax(keepTwoDecimalPlaces(Collections.max(humidityList)))
                        .setHumidityMin(keepTwoDecimalPlaces(Collections.min(humidityList)))
                        .setHumidityAverage(getListAverage(humidityList));
                weatherData.setPressureMax(keepTwoDecimalPlaces(Collections.max(pressureList)))
                        .setPressureMin(keepTwoDecimalPlaces(Collections.min(pressureList)))
                        .setPressureAverage(getListAverage(pressureList));
                weatherData.setIlluminationMax(keepTwoDecimalPlaces(Collections.max(illuminationList)))
                        .setIlluminationMin(keepTwoDecimalPlaces(Collections.min(illuminationList)))
                        .setIlluminationAverage(getListAverage(illuminationList));
                weatherData.setRainfallMax(keepTwoDecimalPlaces(Collections.max(rainfallList)))
                        .setRainfallMin(keepTwoDecimalPlaces(Collections.min(rainfallList)))
                        .setRainfallAverage(getListAverage(rainfallList));
                weatherData.setWindSpeedMax(keepTwoDecimalPlaces(Collections.max(windSpeedList)))
                        .setWindSpeedMin(keepTwoDecimalPlaces(Collections.min(windSpeedList)))
                        .setWindSpeedAverage(getListAverage(windSpeedList));
            }
            // 放入统计集合 输出
            statistics.add(weatherData);
        }
        return statistics;
    }

    /**
     * @param deviceId  设备ID
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 列表
     */
    @Override
    public List<SoilData> soilDataStatistics(String deviceId, String startTime, String endTime) {
        /* 计算时间间隔，按 天 存入 集合 */
        List<String> dates = MyDateUtil.calculateTimeInterval(startTime, endTime);
        if (dates == null) {
            return null;
        }
        List<SoilData> statistics = new ArrayList<>();
        for (String date : dates) {
            // 转换为 unix 时间
            int unixStartTime = Math.toIntExact(MyDateUtil.date2UnixTime(date, "yyyy-MM-dd"));
            int unixEndTime = unixStartTime + 86400;
            // 属性集合
            List<Float> temperature1List = new ArrayList<>();
            List<Float> temperature2List = new ArrayList<>();
            List<Float> temperature3List = new ArrayList<>();
            List<Float> temperature4List = new ArrayList<>();
            List<Float> temperature5List = new ArrayList<>();
            List<Float> humidity1List = new ArrayList<>();
            List<Float> humidity2List = new ArrayList<>();
            List<Float> humidity3List = new ArrayList<>();
            List<Float> humidity4List = new ArrayList<>();
            List<Float> humidity5List = new ArrayList<>();
            List<Float> conductivity3List = new ArrayList<>();
            SoilData soilData = new SoilData();
            soilData.setDate(date);
            List<SoilSenorDataPoints> soilSenorDataPoints = deviceService.selectSoilHistoryData(deviceId, unixStartTime, unixEndTime);
            if (soilSenorDataPoints.size() != 0) {
                // 装载集合
                for (SoilSenorDataPoints soilSenorDataPoint : soilSenorDataPoints) {
                    temperature1List.add(soilSenorDataPoint.getData().getTemperature_1());
                    temperature2List.add(soilSenorDataPoint.getData().getTemperature_2());
                    temperature3List.add(soilSenorDataPoint.getData().getTemperature_3());
                    temperature4List.add(soilSenorDataPoint.getData().getTemperature_4());
                    temperature5List.add(soilSenorDataPoint.getData().getTemperature_5());
                    humidity1List.add(soilSenorDataPoint.getData().getHumidity_1());
                    humidity2List.add(soilSenorDataPoint.getData().getHumidity_2());
                    humidity3List.add(soilSenorDataPoint.getData().getHumidity_3());
                    humidity4List.add(soilSenorDataPoint.getData().getHumidity_4());
                    humidity5List.add(soilSenorDataPoint.getData().getHumidity_5());
                    conductivity3List.add(soilSenorDataPoint.getData().getConductivity_3());
                }
                // 清除集合中的空置，防止空指针异常
                temperature1List.removeIf(Objects::isNull);
                temperature2List.removeIf(Objects::isNull);
                temperature3List.removeIf(Objects::isNull);
                temperature4List.removeIf(Objects::isNull);
                temperature5List.removeIf(Objects::isNull);
                humidity1List.removeIf(Objects::isNull);
                humidity2List.removeIf(Objects::isNull);
                humidity3List.removeIf(Objects::isNull);
                humidity4List.removeIf(Objects::isNull);
                humidity5List.removeIf(Objects::isNull);
                conductivity3List.removeIf(Objects::isNull);

                // set 最大最小值
                if (!temperature1List.isEmpty()) {
                    soilData.setTemperature1Max(keepTwoDecimalPlaces(Collections.max(temperature1List)))
                            .setTemperature1Min(keepTwoDecimalPlaces(Collections.min(temperature1List)))
                            .setTemperature1Average(getListAverage(temperature1List));
                }
                if (!temperature2List.isEmpty()) {
                    soilData.setTemperature2Max(keepTwoDecimalPlaces(Collections.max(temperature2List)))
                            .setTemperature2Min(keepTwoDecimalPlaces(Collections.min(temperature2List)))
                            .setTemperature2Average(getListAverage(temperature2List));
                }
                if (!temperature3List.isEmpty()) {
                    soilData.setTemperature3Max(keepTwoDecimalPlaces(Collections.max(temperature3List)))
                            .setTemperature3Min(keepTwoDecimalPlaces(Collections.min(temperature3List)))
                            .setTemperature3Average(getListAverage(temperature3List));
                }
                if (!temperature4List.isEmpty()) {
                    soilData.setTemperature4Max(keepTwoDecimalPlaces(Collections.max(temperature4List)))
                            .setTemperature4Min(keepTwoDecimalPlaces(Collections.min(temperature4List)))
                            .setTemperature4Average(getListAverage(temperature4List));
                }
                if (!temperature5List.isEmpty()) {
                    soilData.setTemperature5Max(keepTwoDecimalPlaces(Collections.max(temperature5List)))
                            .setTemperature5Min(keepTwoDecimalPlaces(Collections.min(temperature5List)))
                            .setTemperature5Average(getListAverage(temperature5List));
                }
                if (!humidity1List.isEmpty()) {
                    soilData.setHumidity1Max(keepTwoDecimalPlaces(Collections.max(humidity1List)))
                            .setHumidity1Min(keepTwoDecimalPlaces(Collections.min(humidity1List)))
                            .setHumidity1Average(getListAverage(humidity1List));
                }
                if (!humidity2List.isEmpty()) {
                    soilData.setHumidity2Max(keepTwoDecimalPlaces(Collections.max(humidity2List)))
                            .setHumidity2Min(keepTwoDecimalPlaces(Collections.min(humidity2List)))
                            .setHumidity2Average(getListAverage(humidity2List));
                }
                if (!humidity3List.isEmpty()) {
                    soilData.setHumidity3Max(keepTwoDecimalPlaces(Collections.max(humidity3List)))
                            .setHumidity3Min(keepTwoDecimalPlaces(Collections.min(humidity3List)))
                            .setHumidity3Average(getListAverage(humidity3List));
                }
                if (!humidity4List.isEmpty()) {
                    soilData.setHumidity4Max(keepTwoDecimalPlaces(Collections.max(humidity4List)))
                            .setHumidity4Min(keepTwoDecimalPlaces(Collections.min(humidity4List)))
                            .setHumidity4Average(getListAverage(humidity4List));
                }
                if (!humidity5List.isEmpty()) {
                    soilData.setHumidity5Max(keepTwoDecimalPlaces(Collections.max(humidity5List)))
                            .setHumidity5Min(keepTwoDecimalPlaces(Collections.min(humidity5List)))
                            .setHumidity5Average(getListAverage(humidity5List));
                }
                if (!conductivity3List.isEmpty()) {
                    soilData.setConductivity3Max(keepTwoDecimalPlaces(Collections.max(conductivity3List)))
                            .setConductivity3Min(keepTwoDecimalPlaces(Collections.min(conductivity3List)))
                            .setConductivity3Average(getListAverage(conductivity3List));
                }
            }
            // 放入统计集合 输出
            statistics.add(soilData);
        }
        return statistics;
    }

    @Override
    public String weatherHistoryMaxMinAve(String deviceId, int start, int end) throws IOException {
        String session = sessionService.checkSession();
        String authenticationUrl = CreateSignature.mergeAuthenticationUrl(clientId, secret);
        String url = iotUrl + "/v5/clients/" + account + "/devices/" + deviceId + "/public";
        // 发送 HTTP 请求，返回 JSON 信息
        String result = HttpUtils.sendGetAddHeader(url, authenticationUrl + "&begin=" + start + "&end=" + end, "UTF-8", session);
//        return JSON.parseObject(deviceInfo, IotDevice.class);
        return result;
    }

    /**
     * 计算集合平均值 保留两位小数
     *
     * @param list 集合
     * @return 返回平均值
     */
    private static Float getListAverage(List<Float> list) {
        Float sum = 0F;
        if (list.size() != 0) {
            for (Float value : list) {
                sum += value;
            }
            sum = sum / list.size();
            sum = (float) Math.round(sum * 100) / 100;
        }
        return sum;
    }

    /**
     * 保留两位小数
     *
     * @param num 原始数据
     * @return 结果数据
     */
    private static Float keepTwoDecimalPlaces(Float num) {
        return (float) Math.round(num * 100) / 100;
    }
}
